#include <string.h>
#include <unistd.h>
#include "ast/Ast.h"
#include "ir/Unit.h"
#include "machineCode/MachineCode.h"
#include "optimize/pass.h"
#include "optimize/LinearScan.h"
#include "optimize/ElimPHI.h"

Ast ast;
Unit *unit = new Unit();
MachineUnit *mUnit = new MachineUnit();
extern FILE *yyin;
extern FILE *yyout;
extern void clearOperands();
extern void clearSymbolEntries();
extern void clearTypes();
extern void clearMachineOperands();
int yyparse();

char outfile[256] = "a.out";
bool dump_tokens = false;
bool dump_ast = false;
bool dump_ir = false;
bool dump_asm = false;
bool optimize = 1;

int main(int argc, char *argv[]){
    int opt;
    while ((opt = getopt(argc, argv, "Siato:O::")) != -1){
        switch (opt)
        {
        case 'o':
            strcpy(outfile, optarg);
            break;
        case 'a':
            dump_ast = true;
            break;
        case 't':
            dump_tokens = true;
            break;
        case 'i':
            dump_ir = true;
            break;
        case 'S':
            dump_asm = true;
            break;
        case 'O':
            optimize = true;
            break;
        default:
            fprintf(stderr, "Usage: %s [-o outfile] infile\n", argv[0]);
            exit(EXIT_FAILURE);
            break;
        }
    }
    if (optind >= argc){
        fprintf(stderr, "no input file\n");
        exit(EXIT_FAILURE);
    }
    if (!(yyin = fopen(argv[optind], "r"))){
        fprintf(stderr, "%s: No such file or directory\nno input file\n", argv[optind]);
        exit(EXIT_FAILURE);
    }
    if (!(yyout = fopen(outfile, "w"))){
        fprintf(stderr, "%s: fail to open output file\n", outfile);
        exit(EXIT_FAILURE);
    }
    yyparse();
    fprintf(stderr, "ast built\n");
    if (dump_ast){
        ast.output();
        fprintf(stderr, "ast output ok\n");
    }

    ast.genCode(unit);
    fprintf(stderr, "ir generated\n");

    // 中间代码优化
    unitPass(unit);
    if (dump_ir){
        unit->output();
        fprintf(stderr, "ir output ok\n");
    }
    // 优化完了再elimphi
    ElimPHI ep(unit);
    ep.pass();

    if (dump_asm){
        unit->genMachineCode(mUnit);

        LinearScan linearScan(mUnit);
        linearScan.pass();
       
        fprintf(stderr, "asm generated\n");
        mUnit->output();
        fprintf(stderr, "asm output ok\n");
    }
    
    delete mUnit;
    delete unit;
    clearOperands();
    clearSymbolEntries();
    clearTypes();
    clearMachineOperands();
    return 0;
}